from random import Random
from khronos import *
from sfs import *

OPERATOR_SKILLSET = Skillset("Operator", 
                             Skill(convert, lambda: 0*MINUTE), 
                             Skill(load, lambda: 1*MINUTE), 
                             Skill(unload, lambda: 1*MINUTE), 
                             Skill(recover, lambda: 0*MINUTE))

def link_routes(routes, mapping):
    for route in routes:
        linked_sequence = []
        for operation in route.sequence:
            linked_sequence.append(mapping[operation])
        route.sequence = linked_sequence
        
def avoid_conversions(machine, setup, process, products):
    return 2 if machine.setup is setup else 1
    
# ++++++++++++++++++++++++++++++++++++++++++++++++
seed = 1
prod_no = 6
route_no = 3
eqtype_no = 5
ops_per_route = [2, 4]
setups_per_eqtype = [3, 5]
machines_per_op = [5, 20]
personnel_per_op = [1, 5]

# -----------------------
rng = Random(seed)
op_names = "ABCDEFGH"

routes = []
for x in xrange(route_no):
    n_ops = rng.randint(*ops_per_route)
    routes.append(Route("r%d" % (x,), sequence=rng.sample(op_names, n_ops)))
    
products = []
processes = []
releases = []
for x in xrange(prod_no):
    pname = "p%d" % (x,)
    product = Product(pname, rng.choice(routes))
    i = Input(pname)
    o = Output([Bin(pname, lambda: 0.95), Bin("scrap", lambda: 0.05)], mother=i)
    process = Process([i], [o], 
                      tt=lambda: SECOND, 
                      tbf=lambda: 45*MINUTE, 
                      tol=lambda: 10*MINUTE)
    products.append(product)
    processes.append(process)
    releases.append(Release(product, lambda: 4000, lambda: 25*MINUTE))
products.append(Product("scrap", Route("r_scrap", [])))

eqtypes = []
for x in xrange(eqtype_no):
    eqtype = Eq_type("t%d" % (x,))
    for y in xrange(len(processes)):
        eqtype.add_setup("s%d" % (y,), processes=[processes[y]])
    
    conversions = {}
    for y in xrange(len(processes)):
        conversions["s%d" % (y,)] = temp = {}
        for z in xrange(len(processes)):
            if y != z: temp["s%d" % (z,)] = lambda: 15*MINUTE
    eqtype.set_conversions(**conversions)
    eqtypes.append(eqtype)
    
# -----------------------
used_operations = set()
for route in routes:
    used_operations.update(route.sequence)
    
m = Composite("world", children=[Lot_release("entry", config=releases), Sink("exit")])
for opname in used_operations:
    op = Operation(opname, dispatcher_rules=[avoidConversions])
    n_machines = rng.randint(*machines_per_op)
    for x in xrange(n_machines):
        eqtype = rng.choice(eqtypes)
        eqsetup = rng.choice(eqtype.values())
        op.equipment.add(Machine("m%02d" % (x,), type=eqtype, setup=eqsetup))
    n_personnel = rng.randint(*personnel_per_op)
    for x in xrange(n_personnel):
        op.personnel.add(Worker("o%02d" % (x,), skillset=OPERATOR_SKILLSET))
    m.add(op)

m.product_table = dict((p.name, p) for p in products)
m.add(Date_printer(DAY))
link_routes(routes, m)
k = Khronos(m, rng)
